#ifndef SF_ATOMIC_H
#define SF_ATOMIC_H

/**
 * @class SFAtomic
 * @note 对系统内置原子操作进行封装
 *  gcc在4.0.1版本后就通过其内建函数支持原子操作。在这之前编程真必须要通过参考各种cpu的指令操作手册，用其汇编指令编写原子操作。而gcc通过内建函数屏蔽了这些差异。
 */
template<typename T>
class SFAtomic{
public:
    SFAtomic(T val)
        : value(val)
    {}
    // 通过值与旧值进行算术操作，返回新值
    //! 加法操作
    T add(T i)
    {
        return __sync_add_and_fetch(&value, i);
    }
    //! 减法操作
    T sub(T i)
    {
        return __sync_sub_and_fetch(&value, i);
    }
    //! 自增
    T inc()
    {
        return __sync_add_and_fetch(&value, 1);
    }
    T ref()
    {
        return __sync_add_and_fetch(&value, 1);
    }

    //! 自减
    T dec()
    {
        return __sync_sub_and_fetch(&value, 1);
    }
    T deref()
    {
        return __sync_sub_and_fetch(&value, 1);
    }

    //! 取值
    T get()
    {
        volatile T*_val = &value;
        // 内存访问栅
        __sync_synchronize();
        return (*_val);
    }
    //! 赋值
    void set(T val)
    {
        __sync_lock_test_and_set(&value, val);
    }
    T load()
    {
        return get();
    }
    //! 前缀自增
    SFAtomic operator ++()
    {
        __sync_add_and_fetch(&value, 1);
        return *this;
    }
    //! 后缀自增，参数需要加int
    SFAtomic operator ++(int)
    {
        T val = __sync_fetch_and_add(&value, 1);
        return SFAtomic(val);
    }
    //! 前缀自减
    SFAtomic operator --()
    {
        __sync_sub_and_fetch(&value, 1);
        return *this;
    }
    //! 后缀自增
    SFAtomic operator --(int)
    {
        T val = __sync_fetch_and_sub(&value, 1);
        return SFAtomic(val);
    }

    SFAtomic operator+(SFAtomic &val)
    {
        __sync_add_and_fetch(&value, val.value);
        return *this;
    }
    void operator+=(SFAtomic &val)
    {
        __sync_add_and_fetch(&value, val.value);
    }
    SFAtomic operator-(SFAtomic &val)
    {
        __sync_sub_and_fetch(&value, val.value);
        return *this;
    }
    void operator-=(SFAtomic &val)
    {
        __sync_sub_and_fetch(&value, val.value);
    }
    SFAtomic &operator=(const SFAtomic &val)
    {
        __sync_lock_test_and_set(&value, val.value);
        return *this;
    }
    SFAtomic(const SFAtomic &val)
    {
        __sync_lock_test_and_set(&value, val.value);
    }
    bool operator==(const SFAtomic &val)
    {
        return __sync_bool_compare_and_swap(&value, val.value, value);
    }
    bool operator!=(const SFAtomic &val)
    {
        return !__sync_bool_compare_and_swap(&value, val.value, value);
    }
    bool operator==(const SFAtomic &val) const
    {
        return __sync_bool_compare_and_swap(&value, val.value, value);
    }
    bool operator!=(const SFAtomic &val) const
    {
        return !__sync_bool_compare_and_swap(&value, val.value, value);
    }
    //! 原子清零
    void clear()
    {
        __sync_lock_release(&value);
    }
    void swap(SFAtomic &val)
    {
        T _val = value;

        __sync_lock_test_and_set(&value, val.value);
        __sync_lock_test_and_set(&val.value, _val);
    }

private:
    volatile T value;
};

#endif // SF_ATOMIC_H
